#Include _lib\Extend.ahk
#Include _lib\ShinsOverlayClass.ahk
#Include _lib\MouseEvent.ahk
#Include _lib\MeowConf.ahk
#Include _lib\RunCMD.ahk

#NoTrayIcon

CoordMode 'ToolTip'
CoordMode 'Mouse'

w := 165, h := 28, x := a_screenwidth - w, y := a_screenheight - h, opacity := 255
themes := MeowConf.Of('skin/cfg.txt'), theme := themes.Get('default')
sentCnt := 0, receivedCnt := 0

overlay := ShinsOverlayClass(x, y, w, h, 1, 0, 0,)
me := MouseEvent(overlay.hwnd)
me.Register(MouseEvent.Events.LBUTTON_DOWN, MoveWin)
me.Register(MouseEvent.Events.LBUTTON_DBLCLK, (*) => overlay.gui.Move(a_screenwidth - w, a_screenheight - h))
me.Register(MouseEvent.Events.RBUTTON_UP, OnContext)
me.Register(MouseEvent.Events.MOUSE_WHEEL, OnWheel)
adapter := AdapterInfo()

Draw()
SetTimer Draw, 1e3 ; 重绘

Draw(*) {
  overlay.BeginDraw()
  local i := 0, j := 0
  overlay.FillRectangle(i, j, w, h, theme.bgc)
  overlay.DrawImage(Path.Join('skin', theme.bgimg), 0, 0, w, h, 0, 0, w, h, 0.8, 0, 0, 0, 0)
  i += 1, j += 1
  overlay.DrawRectangle(i += 1, j += 1, w - 3, h - 3, theme.borderC)

  local _h := 20
  if adapter.GetActive() {
    speed := adapter.GetNetworkSpeed()
    if speed = 0 {
      overlay.DrawText('无信息', 0, 0, , theme.textC, , 'aCenter aMid')
    } else if speed = -1 {
      overlay.DrawText('已断开', 0, 0, , theme.textC, , 'aCenter aMid')
    } else {
      overlay.DrawText(speed.sent, i, 0, 14, theme.textC, , 'aCenter aMid w80 h' h)
      overlay.DrawLine(i += 82, j + 6, i, _h, theme.lineC)
      overlay.DrawText(speed.received, i, 0, 14, theme.textC, , 'aCenter aMid w80 h' h)
    }
  } else {
    overlay.DrawText('无连接', 0, 0, , theme.textC, , 'aCenter aMid')
  }

  overlay.EndDraw()
  if !me.LD && overlay.GetMousePos(&_, &__) {
    overlay.gui.GetPos(&_x, &_y)
    ToolTip(formatNetworkSpeed(sentCnt) '-' formatNetworkSpeed(receivedCnt), _x, _y - h)
    SetTimer (*) => ToolTip(), -1000
  }
}

MoveWin(*) {
  ToolTip
  MouseGetPos(&px, &py), overlay.gui.GetPos(&wx, &wy)
  dx := wx - px, dy := wy - py
  While GetKeyState("LButton", "P") {
    MouseGetPos(&nx, &ny)
    if nx = px && ny = py
      continue
    overlay.gui.Move(nx + dx, ny + dy)
  }
  WinGetPos(&_x, &_y, &_w, &_h, 'ahk_class Shell_TrayWnd'), overlay.gui.GetPos(&wx, &wy)
  if _x = 0 {
    if _y = 0 {
      (_w > _h) ? overlay.gui.Move(Clamp(wx, 0, A_ScreenWidth - w), Clamp(wy, _h, A_ScreenHeight - h))
      : overlay.gui.Move(Clamp(wx, _w, A_ScreenWidth - w), Clamp(wy, 0, A_ScreenHeight - h)) ; 左侧栏
    } else ; 下侧栏
      overlay.gui.Move(Clamp(wx, 0, A_ScreenWidth - w), Clamp(wy, 0, A_ScreenHeight - h - _h))
  } else { ; 右侧栏
    overlay.gui.Move(Clamp(wx, 0, A_ScreenWidth - w - _w), Clamp(wy, 0, A_ScreenHeight - h))
  }
}

OnWheel(_, up, *) {
  global opacity := Clamp(opacity += (up ? 10 : -10), 100, 255)
  WinSetTransparent(opacity, overlay.gui)
}

OnContext(point, *) {
  ToolTip()
  m := Menu(), sm := Menu(), tm := Menu()
  adapter.adapters.foreach((v, i) => sm.Add(v.name, (*) => adapter.SetActive(i)))
  sm.Add()
  sm.Add('刷新列表', (*) => adapter.RefreshAdapterList())
  if adapter.GetActive()
    sm.Check(adapter.GetActiveAdapterName())
  for k, v in themes.data
    tm.Add(v.desc, SwitchTheme.Bind(k, v.desc))
  tm.Check(theme.desc)
  m.Add('选择网卡', sm), m.SetIcon('选择网卡', 'icon/connection.ico')
  m.Add('切换主题', tm), m.SetIcon('切换主题', 'icon/skn.ico')
  m.Add('重启', (*) => Reload()), m.SetIcon('重启', 'icon/close.ico')
  m.Add('退出', OnExit), m.SetIcon('退出', 'icon/exit.ico')
  m.Show(point.x, point.y)

  SwitchTheme(t, i, *) {
    global theme := themes.Get(t)
  }
}

OnExit(*) {
  SetTimer Draw, 0
  ExitApp()
}

class AdapterInfo {
  static objWMIService := ComObjGet("winmgmts:\\.\root\cimv2")

  __New() {
    this.RefreshAdapterList()
  }

  _GetAdapterList() {
    colNetAdapter := AdapterInfo.objWMIService.ExecQuery("Select * from Win32_NetworkAdapter where NetEnabled=true")
    adapters := []

    for objNetAdapter in colNetAdapter {
      name := objNetAdapter.Name
      name := StrReplace(name, '#', '_')
      name := StrReplace(name, '(', '[')
      name := StrReplace(name, ')', ']')
      adapters.Push({
        name: name,
        guid: objNetAdapter.GUID,
        serviceName: objNetAdapter.ServiceName
      })
    }
    return adapters
  }

  RefreshAdapterList() {
    this.adapters := this._GetAdapterList()
    this.SetActive(this.adapters.Length ? 1 : 0)
  }

  SetActive(i) => this.active := i
  GetActive() => this.active
  GetActiveAdapter() {
    if this.adapters.Length && this.active
      return this.adapters[this.active]
    return {}
  }
  GetActiveAdapterName() => this.GetActiveAdapter()['name']

  GetNetworkSpeed(*) {
    static time1 := 0, bytesReceivedNew := 0, bytesSentNew := 0, bytesSentOld := 0, bytesReceivedOld := 0
    static watch := 0, disconnected := false
    if !this.GetActive()
      return 0
    active := this.GetActiveAdapter()
    WQL := "Select * from Win32_PerfRawData_Tcpip_NetworkInterface where Name='" . active.name . "'"
    RES := AdapterInfo.objWMIService.ExecQuery(WQL)

    if RES.count = 0
      return 0

    for objPerfRawData in RES {
      bytesReceivedOld := bytesReceivedNew, bytesReceivedNew := objPerfRawData.BytesReceivedPerSec
      bytesSentOld := bytesSentNew, bytesSentNew := objPerfRawData.BytesSentPerSec
    }
    if bytesSentNew < bytesSentOld
      bytesSentOld := 0
    if bytesReceivedNew < bytesReceivedOld
      bytesReceivedOld := 0
    if bytesReceivedNew = bytesReceivedOld and bytesSentNew = bytesSentOld
      watch++
    else watch := 0, disconnected := false
    if watch >= 6 {
      if disconnected || 'Up' != RunCMD('powershell -Command "Get-NetAdapter | Where-Object { $_.DeviceID -eq `'' active.guid '`' } | Select-Object -ExpandProperty Status"') {
        disconnected := true
        return -1
      }
    }

    time2 := A_TickCount
    speedReceived := (bytesReceivedNew - bytesReceivedOld) / (time2 - time1) * 1000
    speedSent := (bytesSentNew - bytesSentOld) / (time2 - time1) * 1000
    time1 := time2
    global receivedCnt += speedReceived
    global sentCnt += speedSent
    return {
      received: formatNetworkSpeed(speedReceived),
      sent: formatNetworkSpeed(speedSent)
    }
  }
}

formatNetworkSpeed(bytes) {
  if (bytes < 1024 * 1024) {
    return (bytes / 1024).toFixed(2) " KB" ; 小于 1MB，转换为 KB
  } else if (bytes < 1024 * 1024 * 1024) {
    return (bytes / (1024 * 1024)).toFixed(2) " MB" ; 小于 1GB，转换为 MB
  } else if (bytes < 1024 * 1024 * 1024 * 1024) {
    return (bytes / (1024 * 1024 * 1024)).toFixed(2) " GB" ; 小于 1TB，转换为 GB
  }
}